package com.zhangpf.boot.dao.mongo;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;

import com.mongodb.client.result.UpdateResult;
import com.zhangpf.boot.entity.Page;

/**
 * 
* @ClassName: MongoBaseDAO
* @Description: mongodb基础操作类
* @author zhangpf
* @date 2019年10月25日
* @version V1.0 
* @param <T>
 */
public class MongoBaseDAO<T> {
	
    /**
     * spring mongodb　集成操作类　
     */
    @Resource
    protected MongoTemplate mongoTemplate;
    
    public List<T> findAll() {
        return mongoTemplate.findAll(this.getEntityClass());
    }

    /**
     * 通过条件查询实体(集合)
     *
     * @param query
     */
    public List<T> find(Query query) {
        return mongoTemplate.find(query, this.getEntityClass());
    }

    public List<T> find(Query query, String collectionName) {
        return mongoTemplate.find(query, this.getEntityClass(), collectionName);
    }

    /**
     * 通过一定的条件查询一个实体
     *
     * @param query
     * @return
     */
    public T findOne(Query query) {
        return mongoTemplate.findOne(query, this.getEntityClass());
    }

    public T findOne(Query query, String collectionName) {
        return mongoTemplate.findOne(query, this.getEntityClass(), collectionName);
    }

    /**
     * 通过条件查询更新数据
     *
     * @param query
     * @param update
     * @return
     */
    public void update(Query query, Update update) {
        mongoTemplate.findAndModify(query, update, this.getEntityClass());
    }

    public void update(Query query, Update update, String collectionName) {
        mongoTemplate.findAndModify(query, update, this.getEntityClass(), collectionName);
    }

    public void removeById(String id, String collectionName){
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(id));
        mongoTemplate.remove(query, collectionName);
    }
    
    public void removeById(String id){
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(id));
        mongoTemplate.remove(query, this.getEntityClass());
    }
    
    public void removeByEntity(Object entity){
        mongoTemplate.remove(entity);
    }

    /**
     * 保存一个对象到mongodb
     *
     * @param entity
     * @return
     */
    public T save(T entity) {
        return mongoTemplate.insert(entity);
    }
    
    public void save(List<T> entity) {
        mongoTemplate.insert(entity, this.getEntityClass());
    }

    public T save(T entity, String collectionName) {
        return mongoTemplate.insert(entity, collectionName);
    }
    
    /**
     * @return 
    * @Title: updateSelective
    * @Description: 如果属性为null则不更新，有值才更新
    * @param @param entity
    * @return void
    * @throws
     */
    public long updateSelective(T entity) {
		Map<String, Object> map = null;
		try {
			map = parseEntity(entity);
		}catch (Exception e) {
			e.printStackTrace();
		}
		String idKey = null;
		Object idValue = null;
		Update update = new Update();
		if(map!=null && map.size()>0) {
			for(Map.Entry<String, Object> entry : map.entrySet()) {
				String key = entry.getKey();
				Object value = entry.getValue();
				if(key.startsWith("{")) {
					idKey = key.substring(key.indexOf("{")+1,key.indexOf("}"));
					idValue = map.get(key);
				}else {
					if (value != null) {
						update.set(key, value);
					}
				}
			}
		}
		return mongoTemplate.updateFirst(new Query().addCriteria(Criteria.where(idKey).is(idValue)), update, getEntityClass()).getModifiedCount();
	}
    
    /**
    * @Title: saveOrUpdate
    * @Description: 保存或更新,如果ID已经存在则更新所有属性，不存在则新增一条记录
    * @param @param entity
    * @param @return
    * @return T
    * @throws
     */
    public T saveOrUpdate(T entity) {
        return mongoTemplate.save(entity);
    }

    /**
     * 通过ID获取记录
     *
     * @param id
     * @return
     */
    public T findById(String id) {
        return mongoTemplate.findById(id, this.getEntityClass());
    }

    /**
     * 通过ID获取记录,并且指定了集合名(表的意思)
     *
     * @param id
     * @param collectionName
     *            集合名
     * @return
     */
    public T findById(String id, String collectionName) {
        return mongoTemplate.findById(id, this.getEntityClass(), collectionName);
    }

    /**
     * 分页查询
     * @param page
     * @param query
     * @return
     */
    public Page<T> findPage(Page<T> page, Query query){
        long count = this.count(query);
        page.setTotal(Long.valueOf(count).intValue());
        int pageNumber = page.getPageNo();
        int pageSize = page.getPageSize();
        query.skip((pageNumber - 1) * pageSize).limit(pageSize);
        List<T> rows = this.find(query);
        page.setRows(rows);
        return page;
    }

    public Page<T> findPage(Page<T> page, Query query, String collectionName){
        long count = this.count(query, collectionName);
        page.setTotal(Long.valueOf(count).intValue());
        int pageNumber = page.getPageNo();
        int pageSize = page.getPageSize();
        query.skip((pageNumber - 1) * pageSize).limit(pageSize);
        List<T> rows = this.find(query, collectionName);
        page.setRows(rows);
        return page;
    }

    /**
     * 求数据总和
     * @param query
     * @return
     */
    public long count(Query query){
        return mongoTemplate.count(query, this.getEntityClass());
    }

    public long count(Query query, String collectionName){
        return mongoTemplate.count(query, this.getEntityClass(), collectionName);
    }
    
    public List<T> findByAggregation(Aggregation aggregation){
    	return mongoTemplate.aggregate(aggregation,this.getEntityClass(), this.getEntityClass()).getMappedResults();
    }
    
    public List<T> findByAggregation(Aggregation aggregation, String collectionName){
    	return mongoTemplate.aggregate(aggregation,collectionName, this.getEntityClass()).getMappedResults();
    }

    /**
     * 获取需要操作的实体类class
     *
     * @return
     */
    @SuppressWarnings("unchecked")
	public Class<T> getEntityClass(){
        return (Class<T>)((ParameterizedType)getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    }
    
    protected Map<String, Object> parseEntity(T t) throws Exception{
		Map<String, Object> map = new HashMap<>();
		String id = "";
		Field[] declaredFields = getEntityClass().getDeclaredFields();
		for(Field field:declaredFields) {
			if(field.isAnnotationPresent(Id.class)) {
				field.setAccessible(true);
				map.put("{"+field.getName()+"}", field.get(t));
				id = field.getName();
				break;
			}
		}
		
		Method[] declaredMethods = getEntityClass().getDeclaredMethods();
		if( declaredFields != null&& declaredFields.length > 0 ) {
			for(Method method:declaredMethods) {
				if(method.getName().startsWith("get")&&method.getModifiers()==Modifier.PUBLIC) {
					String fieldName = parse2FieldName(method.getName());
					if(!fieldName.equals(id)) {
						map.put(fieldName, method.invoke(t));
					}
				}
			}
		}
		return map;
	}
    
    private String parse2FieldName(String method) {
		String name = method.replace("get", "");
		name = name.substring(0, 1).toLowerCase()+name.substring(1);
		return name;
	}
}